<?php

namespace Sharks\Core\Http\Routing;

use Sharks\Core\Cfg\AppConfig;
use Sharks\Core\Support\Bag\Bag;

/**
 * Routing 分析
 * FIXME: 1. route文件的正确性检查; 2. 处理过程有些冗杂
 */
class RouteResolve {

    private $routes;
    private $handledRoutes;
    private $verb;
    private $pathinfo;

    public function __construct(array $routes, Bag $handledRoutes, $pathinfo, $verb) {
        $this->routes = $routes;
        $this->handledRoutes = $handledRoutes;
        $this->verb = strtoupper($verb);
        $this->pathinfo = $pathinfo;
    }

    /**
     * Url 分析
     */
    public function resolve() {
        // http verb 重写
        $routeMethodNaming = AppConfig::get('route_method_naming', '_method');
        if (isset($_REQUEST[$routeMethodNaming])) {
            $this->verb = strtoupper($_REQUEST[$routeMethodNaming]);
        }

        // 先检查已处理过的结果集，有处理过的结果集就返回
        if ($this->handledRoutes->has($this->verb, $this->pathinfo)) {
            return $this->handledRoutes->get($this->verb, $this->pathinfo);
        }

        // 解析
        $result = $this->_resolve($this->pathinfo, $this->verb);

        if (!is_null($result)) {
            $this->handledRoutes->put($this->verb . $this->pathinfo, $result);
        }
        else {//如果找不到结果，则也返回Route数据，但isHit=false
            $result = new RouteResolveResult();
            $result->isHit = false;
        }
        return $result;
    }

    /**
     * 解析Uri
     * @param  [type] $pathinfo [description]
     * @param  [type] $verb     [description]
     * @return [type]           [description]
     */
    private function _resolve($pathinfo, $verb) {
        $urlKey = $verb . $pathinfo;

        if (isset($this->routes[$urlKey])) {
            $routeMap = $this->routes[$urlKey];
            if (array_key_exists('map', $routeMap)) {// 映射类型route
                $mapResult = new RouteResolveResult();
                $mapResult->url = $pathinfo;
                $mapResult->verb = $verb;
                $mapResult->originalRoute = $routeMap['route'];

                $result = $this->_resolve($routeMap['map']['route'], $verb);
                $result->mapResult = $mapResult;

                return $result;
            }
            else {//非映射类型

                $result = new RouteResolveResult();
                $result->url = $pathinfo;
                $result->verb = $verb;
                $result->originalRoute = $routeMap['route'];
                $result->module = $routeMap['action']['module'];
                $result->controller = $routeMap['action']['controller'];
                $result->method = $routeMap['action']['method'];
                $result->middlewares = $routeMap['middlewares'];

                return $result;

            }
        }
        else {
            // 检查RouteMap
            foreach ($this->routes as $key => $routeMap) {

                if (!isset($routeMap["routeRexPattern"])) { // 无参数
                    continue;
                } elseif ($routeMap['verb'] === $verb
                    && array_key_exists('routeRexPattern', $routeMap)
                    && preg_match_all($routeMap['routeRexPattern'], $pathinfo, $matches)
                ) { // 有参数

                    // 解析参数
                    $parameters = $routeMap['parameters'];
                    $params = array();
                    foreach (array_slice($matches, 1) as $matche) {
                        $params[] = $matche[0];
                    }
                    // 生成参数
                    $params = array_combine($parameters, $params);

                    if (array_key_exists('map', $routeMap)) {// 映射类型route

                        $mapResult = new RouteResolveResult();
                        $mapResult->url = $pathinfo;
                        $mapResult->verb = $verb;
                        $mapResult->originalRoute = $routeMap['route'];
                        $mapResult->parameters = $params;

                        // 使用参数替换映射 route
                        $mapRoute = $routeMap['map']['route'];
                        foreach ($routeMap['parameters'] as $newP => $oldP) {
                            str_replace('{' . $oldP . '}', $params[$newP], $mapRoute);
                        }
                        $result = $this->_resolve($mapRoute, $verb);
                        $result->mapResult = $mapResult;

                    } else {//非映射类型
                        $result = new RouteResolveResult();
                        $result->url = $pathinfo;
                        $result->verb = $verb;
                        $result->originalRoute = $routeMap['route'];
                        $result->module = $routeMap['action']['module'];
                        $result->controller = $routeMap['action']['controller'];
                        $result->method = $routeMap['action']['method'];
                        $result->middlewares = $routeMap['middlewares'];
                        $result->parameters = $params;

                        return $result;
                    }
                }
            }
        }
        return null;
    }
}